//-----------------------------------------------------------------------
// <copyright file="TupleLinkedListPool.cs" company="tuliprules.org">
//     Copyright (c) 2010 tuplelister, tuliprules.org.
// </copyright>
// <summary>This is the TupleLinkedListPool class.</summary>
//-----------------------------------------------------------------------

// #define NOPOOL
namespace Tulip.Engine.Tuples
{
    using System.Collections.Generic;
    using System.Diagnostics;

    /// <summary>
    /// Maintains a pool of available TupleLinkedLists.   The pool is partitioned by Tuple type.
    /// </summary>
    /// <remarks>
    /// <para>Pooling Tuple linked lists is a significant optimisation where a large number of facts are
    /// handled by the engine, and where there is a lot of retraction and reassertion of Facts.
    /// By pooling and recycling Tuple instances, garbage collection of Tuples during execution of
    /// a ruleset can be eliminated, and the cost of instantiation can be  reduced.   Miss Manners
    /// benchmarking showed an approx 20% improvement in performance with pooling switched on.</para>
    /// <para>The TupleLinkedListPool is a global singleton that acts as a class factory and instance recycler.</para>
    /// </remarks>
    internal static class TupleLinkedListPool
    {
        /// <summary>
        /// Stores pooled tuples.   The repository is partitioned by tuple type.
        /// </summary>
        private static readonly List<TupleLinkedList> TupleLinkedListRepository = new List<TupleLinkedList>();

        ////////private static TupleLinkedList _dummyLinkedList = new TupleLinkedList();

        /// <summary>
        /// Gets a Tuple Linked List.   This may be a recycled Tuple Linked List from the pool, or, if the
        /// pool is empty, a new Tuple Linked List.
        /// </summary>
        /// <param name="indexerId">
        /// Unique identifier used for the tuple linked list. 
        /// </param>
        /// <returns>
        /// A Tuple link instance.
        /// </returns>
        public static TupleLinkedList GetItem(int indexerId)
        {
#if NOPOOL
            Tuple recycledTuple = null;
            recycledTuple = (Tuple)Activator.CreateInstance(tupleClass);
            recycledTuple.IsPooled = false;
            return recycledTuple;
#else
            // TODO: Consider using a weak reference to allow garbage collection.

            ////if (indexerId == 0) return _dummyLinkedList;

            TupleLinkedList recycledTupleLinkedList;

            if (TupleLinkedListRepository.Count == 0)
            {
                // There are no tuple linked lists in the repository
                recycledTupleLinkedList = new TupleLinkedList();
            }
            else
            {
                recycledTupleLinkedList = TupleLinkedListRepository[TupleLinkedListRepository.Count - 1];
                TupleLinkedListRepository.RemoveAt(TupleLinkedListRepository.Count - 1);
                recycledTupleLinkedList.Clear();
            }

            recycledTupleLinkedList.IndexerId = indexerId;
            recycledTupleLinkedList.IsPooled = false;
            return recycledTupleLinkedList;
#endif
        }

        /// <summary>
        /// Releases a tuple list back to the pool.
        /// </summary>
        /// <param name="returnedTupleLinkedList">The tuple list to be returned to the pool.</param>
        public static void ReturnItem(TupleLinkedList returnedTupleLinkedList)
        {
#if NOPOOL
            returnedTupleLinkedList.Clear();
#else
            Debug.Assert((returnedTupleLinkedList != null), "The returned TupleLinkedList cannot be null");

            TupleLinkedListRepository.Add(returnedTupleLinkedList);
            returnedTupleLinkedList.IsPooled = true;
#endif
        }
    }
}
